﻿using Spider.Framework.UtilityCommon;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Spider.Framework.UtilityCommon.Extensions;
using MyCrawler.Entity;
using MyCrawler.Utilyties;
using System.Threading;

namespace MyCrawler.Controls
{
    public class PhuNuVnCtr : ForumsCtr
    {
        private int _secondSleep;

        /// <summary>
        /// XenForo
        /// </summary>
        public PhuNuVnCtr()
        {
            _source = "phunuvn.net";
            _linkInit = "http://phunuvn.net/";
            _domain = "http://phunuvn.net/"; // dùng cho các trang sub trở đi, vì sẽ nối trang với domain
            _blockId = DateTime.Now.ToString("yyyyMMddhhmmss");
            _pageLimit = -1;
            _secondSleep = 15000; // thời gian chờ 30 giây cho 1 lần truy cập link kế, trang này cần phải thế không nó lock Ip
        }

        /// <summary>
        /// Contructor thứ 2
        /// </summary>
        /// <param name="source">nguồn</param>
        /// <param name="linkInit">link khởi tạo</param>
        /// <param name="domain">domain gốc - có thể trùng với link khởi tạo</param>
        /// <param name="blockId">mỗi lần khởi tạo sẽ có 1 block id, chứa list các thread</param>
        public PhuNuVnCtr(string source, string linkInit, string domain, string blockId)
        {
            _source = source;
            _linkInit = linkInit;
            _domain = domain; // dùng cho các trang sub trở đi, vì sẽ nối trang với domain
            _blockId = blockId;

            _pageLimit = -1;
            _secondSleep = 15000; // thời gian chờ 30 giây cho 1 lần truy cập link kế, trang này cần phải thế không nó lock Ip
        }

        public override List<string> GetCatalogByLink()
        {
            try
            {
                string html = GetContentWithStream(_linkInit, -1);
                List<string> ls_L1 = UtilityCtr.GetListItem(html, @"<div class='categoryText'><h3 class='nodeTitle'><a.*?<\/h3>");

                List<string> lsLinkStored = new List<string>();
                for (int i = 0; i < ls_L1.Count; i++)
                {
                    #region làm việc với link catagories cấp 1
                    string link_l1 = _domain + UtilityCtr.GetItemFirst(ls_L1[i], @"href='.*?'").Replace("href='", "").Replace("'", "");

                    // tạm nghỉ mấy giây không nó block Ip của mình
                    Thread.Sleep(_secondSleep);
                    html = GetContentWithStream(link_l1, -1);

                    // kiểm tra Sub 1 có List topic hay không
                    bool hasThread = Regex.IsMatch(html, @"<li[\s]+id='thread-[\d]+'");
                    if (hasThread == true)// có các topic, đưa link vào list để lọc topic
                    {
                        lsLinkStored.Add(link_l1);
                    }

                    // danh sách các link của danh mục sub 2 - nếu có
                    List<string> ls_L2 = UtilityCtr.GetListItem(html, @"<h3[\s]+class='nodeTitle'>.*?<\/h3>");
                    for (int j = 0; j < ls_L2.Count; j++)
                    {
                        #region làm việc với link catagories cấp 2
                        string link_l2 = _domain + UtilityCtr.GetItemFirst(ls_L2[j], @"href='.*?'").Replace("href='", "").Replace("'", "");

                        // tạm nghỉ mấy giây không nó block Ip của mình
                        Thread.Sleep(_secondSleep);
                        html = GetContentWithStream(link_l2, -1);

                        // kiểm tra Sub 2 có List topic hay không
                        hasThread = Regex.IsMatch(html, @"<li[\s]+id='thread-[\d]+'");
                        if (hasThread == true)// có các topic, đưa link vào list để lọc topic
                        {
                            lsLinkStored.Add(link_l2);
                        }

                        // danh sách các link của danh mục sub 3 - nếu có 
                        List<string> ls_L3 = UtilityCtr.GetListItem(html, @"<h3[\s]+class='nodeTitle'>.*?<\/h3>");
                        for (int k = 0; k < ls_L3.Count; k++)
                        {
                            #region làm việc với link catagories cấp 3
                            string link_l3 = _domain + UtilityCtr.GetItemFirst(ls_L3[k], @"href='.*?'").Replace("href='", "").Replace("'", "");

                            if (!link_l3.Contains("link-forums"))
                            {
                                // tạm nghỉ mấy giây không nó block Ip của mình
                                Thread.Sleep(_secondSleep);
                                /// truy cập vào trang sub 3 nếu có
                                html = GetContentWithStream(link_l3, -1);

                                // kiểm tra Sub 3 có List topic hay không
                                hasThread = Regex.IsMatch(html, @"<li[\s]+id='thread-[\d]+'");
                                if (hasThread == true)// có các topic, đưa link vào list để lọc topic
                                {
                                    lsLinkStored.Add(link_l3);
                                }

                                // truy cập để tìm 'forum sub' cấp 4
                                List<string> ls_L4 = UtilityCtr.GetListItem(html, @"<h3[\s]+class='nodeTitle'>.*?<\/h3>");
                                for (int l = 0; l < ls_L4.Count; l++)
                                {
                                    // làm việc với link catagories cấp 4
                                    string link_l4 = _domain + UtilityCtr.GetItemFirst(ls_L4[l], @"href='.*?'").Replace("href='", "").Replace("'", "");
                                    lsLinkStored.Add(link_l4);
                                }
                            }
                            #endregion
                        }
                        #endregion
                    }
                    #endregion
                }
                return lsLinkStored;
            }
            catch { }
            return null;
        }

        public override void GetListTopic_InCatagory(string lnkCat)
        {
            try
            {
                TraceLog_Status(_source, _blockId, " + " + lnkCat);

                string s = GetWebContent(lnkCat, -1);

                if (s.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                // lấy các chủ đề ngày trang đầu
                GetTopicsInPage(s, 1);

                #region  lấy các chủ đề từ trang thứ 2 trờ đi - nếu có
                try
                {
                    string pager = UtilityCtr.GetItemFirst(s, @"Trang[\s]+[\d]+[\s]+của[\s]+[\d]+[\s]+trang");
                    List<string> lsNumPage = UtilityCtr.GetListItem(pager, @"[\d]+");

                    int totalPage = Convert.ToInt32(lsNumPage[lsNumPage.Count - 1]);
                    _pageLimit = -1; // khởi tạo trang giới hạn
                    for (int j = 2; j <= totalPage; j++) // duyêt từ trang số 2 trở đi
                    {
                        if (_pageLimit != -1 && j > _pageLimit) // đã tìm thấy trang giới hạn, trang này có ngày cập nhật nhỏ hơn ngày giới hạn
                        {
                            break;
                        }

                        // cứ 2 topic ta nghỉ 1 số giây để tránh nó block Ip của mình
                        if (j % 2 == 0)
                        {
                            Thread.Sleep(_secondSleep);
                        }

                        s = GetWebContent(lnkCat + "page-" + j, -1);

                        if (s.IsStringNullOrEmpty())
                        {
                            TraceLog_Status(_source, _blockId, " --- Trang số " + j.ToString() + ": Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                            continue;
                        }

                        GetTopicsInPage(s, j); // lấy các chủ đề của trang 1
                    }
                }
                catch { }
                #endregion
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, " --- Error: " + ex.Message);
            }
        }

        private void GetTopicsInPage(string contentHtml, int pageIndex)
        {
            try
            {
                var lisTopic = contentHtml.GetElements(@"(<li[\s]+id='thread-[\d]+').*?(<\/div><\/li>)", false, PatternType.Regex);

                if (lisTopic == null || lisTopic.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- không tìm thấy Topic, kiểm tra Catagorie này có thay đổi source code!"); // ghi log để test
                    return;
                }

                for (int i = 0; i < lisTopic.Count; i++)
                {
                    List<string> lsDate = UtilityCtr.GetListItem(lisTopic[i], @"[\d]+[\s]+[\D]+[\s]+[\d]+");

                    if (lsDate.Count == 0)
                    {
                        TraceLog_Status(_source, _blockId, " --- Ngày 'last reply' không tồn tại, có thể chủ đề đã bị xóa, đã di chuyển, hay website nguồn có sự thay đổi souce code!");
                        continue;
                    }

                    string strDate = lsDate[lsDate.Count - 1]; // dạng: 18 Tháng hai 2014

                    if (strDate != "")
                    {
                        try
                        {
                            string sDay = UtilityCtr.GetItemFirst(strDate, @"^[\d]+");
                            string sYear = UtilityCtr.GetItemFirst(strDate, @"[\d]+$");

                            string sMonth = UtilityCtr.GetItemFirst(strDate, @"[\D]+").ToLower().Trim();

                            string day = "";
                            switch (sMonth)
                            {
                                case "tháng một":
                                    day = sYear + "-01-" + sDay;
                                    break;
                                case "tháng hai":
                                    day = sYear + "-02-" + sDay;
                                    break;
                                case "tháng ba":
                                    day = sYear + "-03-" + sDay;
                                    break;
                                case "tháng tư":
                                    day = sYear + "-04-" + sDay;
                                    break;
                                case "tháng năm":
                                    day = sYear + "-05-" + sDay;
                                    break;
                                case "tháng sáu":
                                    day = sYear + "-06-" + sDay;
                                    break;
                                case "tháng bảy":
                                    day = sYear + "-07-" + sDay;
                                    break;
                                case "tháng tám":
                                    day = sYear + "-08-" + sDay;
                                    break;
                                case "tháng chín":
                                    day = sYear + "-09-" + sDay;
                                    break;
                                case "tháng mười":
                                    day = sYear + "-10-" + sDay;
                                    break;
                                case "tháng mười một":
                                    day = sYear + "-11-" + sDay;
                                    break;
                                case "tháng mười hai":
                                    day = sYear + "-12-" + sDay;
                                    break;
                                default:
                                    day = sYear + "-01-" + sDay;
                                    break;
                            }

                            string strHour = "00:00";

                            List<string> lsHour = UtilityCtr.GetListItem(lisTopic[i], @"[\d]+:[\d]+'>");
                            if (lsHour.Count > 0)
                            {
                                strHour = lsHour[lsHour.Count - 1].Replace("'>", "");
                            }

                            day = day + " " + strHour;

                            DateTime dtLastDate = Convert.ToDateTime(day);

                            // kiểm tra ngày này có nhỏ hơn ngày giới hạn lấy hay không?
                            if (dtLastDate >= _dtLimit)// trong thời gian 30 ngày mà không có ai trả lời, không lấy dữ liệu mới về nữa
                            {
                                #region thực hiện lấy data
                                string lnTopic = _domain + UtilityCtr.GetItemFirst(lisTopic[i], @"(href='threads\/).*?'").Replace("href='", "").Replace("'", "");

                                if (lnTopic.IsStringNullOrEmpty() == true)
                                {
                                    TraceLog_Status(_source, _blockId, " --- Link của topic rỗng, có thể website nguồn có sự thay đổi souce code!");
                                    continue; // chạy tới topic kế mà không quan tâm đoạn dưới
                                }

                                string topicSub = UtilityCtr.GetItemFirst(lisTopic[i], @"(<a href='threads\/).*?<\/a>");
                                topicSub = Regex.Replace(topicSub, @"<.*?>", "");

                                int id;
                                try
                                {
                                    id = Convert.ToInt32(lnTopic.GetElement(@".[\d]+", false, PatternType.Regex).Replace(".", ""));
                                }
                                catch
                                {
                                    id = 0;
                                }

                                #endregion

                                // cứ 2 topic ta nghỉ 1 số giây để tránh nó block Ip của mình
                                if (i % 2 == 0)
                                {
                                    Thread.Sleep(_secondSleep);
                                }

                                GetContent(lnTopic, topicSub, id, dtLastDate);
                            }
                            else
                            {
                                if (pageIndex > 1) // nếu đây là trang thứ 2 trở đi
                                {
                                    _pageLimit = pageIndex; // đánh dấu trang hiện hành này là trang giới hạn, vì các chủ để từ trang sau luôn có ngày reply nhỏ hơn ngày giới hạn
                                    break;
                                }
                            }

                        }
                        catch (Exception ex)
                        {
                            TraceLog_Status(_source, _blockId, " --- Error: " + ex.Message);
                        }
                    }
                }
            }
            catch
            { }
        }

        public void GetContent(string lnk, string sub, long idTopic, DateTime lastModify)
        {
            try
            {
                // ghi log để test
                TraceLog_Status(_source, _blockId, " --- " + lnk);

                string html = GetWebContent(lnk, -1);

                if (html.IsStringNullOrEmpty())
                {
                    TraceLog_Status(_source, _blockId, " --- --- Data null Or empty. WebClient request time out. Kiểm tra Website có bị chết hay không hay kiểm tra kết nối internet của bạn! "); // ghi log để test
                    return;
                }

                #region lấy tên danh mục
                var catLis = html.GetElements(@"<span itemprop='title'>.*?<\/span>", false, PatternType.Regex);

                string catName = "";
                if (catLis == null || catLis.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Lấy tên danh mục trên thanh navigation rỗng, có thể website nguồn có sự thay đổi souce code!");
                }
                else
                {
                    catName = catLis[catLis.Count - 1];
                    catName = Regex.Replace(catName, @"<.*?>", "").Trim();
                }
                #endregion

                var lisPost = html.GetElements(@"<div class='messageContent'><article><blockquote.*?<\/blockquote><\/article><\/div>", false, PatternType.Regex);

                if (lisPost == null || lisPost.Count == 0)
                {
                    TraceLog_Status(_source, _blockId, " --- --- Bài viết và Bình luận = 0, có thể website nguồn có sự thay đổi souce code, hay ip bị block!");
                    return;
                }

                // lấy nội dung bài viết - chính là post đầu tiên
                string cont = Regex.Replace(lisPost[0], @"<.*?>", " ");
                // replace nhiều khoảng trắng thành 1 khoảng trắng
                cont = Regex.Replace(cont, @"[\s]+", " ").Trim();

                #region [lấy bình luận trang đầu]
                List<string> lsCmt = new List<string>();
                for (int i = 1; i < lisPost.Count; i++)
                {
                    string cmt = Regex.Replace(lisPost[i], @"<.*?>", " ");
                    cmt = Regex.Replace(cmt, @"[\s]+", " ").Trim();//replace nhiều khoảng trắng thành 1 khoảng trắng

                    if (cmt.IsStringNullOrEmpty() == false)
                    {
                        lsCmt.Add(cmt);
                    }
                }
                #endregion

                #region lấy bình luận từ trang 2 trở đi
                try
                {
                    string pager = html.GetElement(@"Trang[\s]+[\d]+[\s]+của[\s]+[\d]+[\s]+trang", false, PatternType.Regex);
                    List<string> lsNumPage = UtilityCtr.GetListItem(pager, @"[\d]+");

                    int totalPage = Convert.ToInt32(lsNumPage[lsNumPage.Count - 1]);
                    for (int i = 2; i <= totalPage; i++) // duyêt từ trang số 2 trở đi
                    {
                        // cứ 2 trang bình luận ta nghỉ 1 số giây để tránh nó block Ip của mình
                        if (i % 2 == 0)
                        {
                            Thread.Sleep(_secondSleep);
                        }

                        string lnkSub = lnk + "page-" + i.ToString();
                        string htmlSub = GetWebContent(lnkSub, -1);

                        /// lấy danh sách
                        var lisPostSub = UtilityCtr.GetListItem(htmlSub, @"<div class='messageContent'><article><blockquote.*?<\/blockquote><\/article><\/div>");
                        for (int j = 0; j < lisPostSub.Count; j++)
                        {
                            string cmtsub = Regex.Replace(lisPostSub[j], @"<.*?>", "");
                            //replace nhiều khoảng trắng thành 1 khoảng trắng
                            cmtsub = Regex.Replace(cmtsub, @"[\s]+", " ").Trim();

                            if (cmtsub.IsStringNullOrEmpty() == false)
                            {
                                lsCmt.Add(cmtsub);
                            }
                        }
                    }
                }
                catch { }

                #endregion

                #region [Lưu lại]

                ContentEntity entity = new ContentEntity();

                entity.Category = catName;
                entity.Comments = lsCmt;
                entity.Content = cont;
                entity.Id = idTopic;
                entity.LastModify = lastModify;
                entity.Link = lnk;
                entity.Source = _source;
                entity.Summury = "";
                entity.Title = sub;

                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- Comments: " + lsCmt.Count.ToString() + " -- Last modify: " + lastModify.ToString("yyyy-MM-dd hh:mm:ss tt"));
                // lưu vào file json
                string file = LogFileJson(entity);
                // ghi log để review
                TraceLog_Status(_source, _blockId, " --- --- File json: " + file);

                // tăng số topic lên 1 để thực hiện việc thống kê
                _totalTopic = _totalTopic + 1;
                UtilityCtr.TraceSettingTime(_source, _timeStart, _totalTopic, _dtLimit.ToString("yyyy-MM-dd hh:mm:ss tt"));
                #endregion
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, " --- --- Error: " + ex.Message); // ghi log để test
            }
        }

    }
}
